package com.redmoon.oa.flow;

import cn.js.fan.util.*;
import com.cloudweb.oa.api.IFormProUtil;
import com.cloudweb.oa.api.ILicenseUtil;
import com.cloudweb.oa.cache.FormArchiveCache;
import com.cloudweb.oa.service.FormArchiveService;
import com.cloudweb.oa.utils.LicenseConstUtil;
import com.cloudweb.oa.utils.SpringUtil;
import com.cloudwebsoft.framework.util.LogUtil;
import com.redmoon.oa.Config;
import com.redmoon.oa.LogDb;
import com.redmoon.oa.kernel.License;
import com.redmoon.oa.sys.DebugUtil;
import com.redmoon.oa.visual.ModuleSetupDb;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.xml.sax.InputSource;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.Iterator;
import java.util.List;

/**
 * @author fgf
 */
public class FormMgr {
    public FormMgr() {
    }

    public FormDb getFormDb(String code) {
        FormDb ftd = new FormDb();
        return ftd.getFormDb(code);
    }

    public synchronized boolean move(HttpServletRequest request) throws
            ErrMsgException {
        FormForm fc = new FormForm();
        fc.checkMove(request);

        FormDb ft = getFormDb(fc.getFormDb().getCode());
        return ft.move(fc.getDirection());
    }

    public synchronized boolean create(HttpServletRequest request) throws
            ErrMsgException {
        // 许可证验证
        // License.getInstance().validate(request);

        FormForm fc = new FormForm();
        fc.checkCreate(request);

        String ieVersion = ParamUtil.get(request, "ieVersion");

        FormDb ft = fc.getFormDb();
        ft.setIeVersion(ieVersion);

        String fieldsAry = ParamUtil.get(request, "fieldsAry");
        FormParser fp = new FormParser();
        try {
            JSONArray ary = new JSONArray(fieldsAry);
            fp.getFields(ary);
        } catch (JSONException e) {
            LogUtil.getLog(getClass()).error(e);
            throw new ErrMsgException(e.getMessage());
        }
        ft.setFormParser(fp);

        boolean re = ft.create();
        if (re) {
            FormArchiveService formArchiveService = SpringUtil.getBean(FormArchiveService.class);
            formArchiveService.create(SpringUtil.getUserName(), ft.getCode(), ft.getContent());

            // 生成模块
            ModuleSetupDb msd = new ModuleSetupDb();
            msd.getModuleSetupDbOrInit(ft.getCode());
        }
        return re;
    }

    public synchronized boolean del(String code) throws ErrMsgException {
        Leaf lf = new Leaf();
        for (Object o : lf.getLeavesUseForm(code)) {
            lf = (Leaf) o;
            WorkflowDb wfd = new WorkflowDb();
            int count = wfd.getWorkflowCountOfType(lf.getCode());
            if (count > 0) {
                throw new ErrMsgException("流程 " + lf.getName() + " 中已有流程 " + count + " 个，表单不能被删除！");
            }
        }

        FormDb fd = new FormDb();
        fd = fd.getFormDb(code);
        boolean re = fd.del();
        if (re) {
            // 记录日志
            HttpServletRequest request = SpringUtil.getRequest();
            com.redmoon.oa.LogUtil.log(SpringUtil.getUserName(), StrUtil.getIp(request), LogDb.TYPE_ACTION, "FORM_DEL " + fd.getName() + ":" + fd.getCode());

            FormArchiveCache formArchiveCache = SpringUtil.getBean(FormArchiveCache.class);
            formArchiveCache.refreshAll(code);
        }
        return re;
    }

    public synchronized boolean modify(HttpServletRequest request) throws ErrMsgException {
        // 许可性验证
        // License.getInstance().validate(request);

        FormForm fc = new FormForm();
        fc.checkModify(request);

        FormDb ft = fc.getFormDb();

        FormDb ftd = getFormDb(ft.getCode());
        ftd.setName(ft.getName());
        ftd.setOldContent(ftd.getContent());
        ftd.setContent(ft.getContent());
        ftd.setFlowTypeCode(ft.getFlowTypeCode());
        ftd.setHasAttachment(ft.isHasAttachment());

        String ieVersion = ParamUtil.get(request, "ieVersion");
        ftd.setIeVersion(ieVersion);
        ftd.setLog(ft.isLog());
        ftd.setProgress(ft.isProgress());

        ftd.setUnitCode(ft.getUnitCode());
        ftd.setOnlyCamera(ft.isOnlyCamera());
        ftd.setFlow(ft.isFlow());
        ftd.setPageStyle(ft.getPageStyle());
        ftd.setViewRuleMode(ft.getViewRuleMode());

        String fieldsAry = ParamUtil.get(request, "fieldsAry");
        FormParser fp = new FormParser();
        try {
            JSONArray ary = new JSONArray(fieldsAry);
            fp.getFields(ary);
        } catch (JSONException e) {
            DebugUtil.i(getClass(), "modify", fieldsAry);
            LogUtil.getLog(getClass()).error(e);
            throw new ErrMsgException(e.getMessage());
        }
        ftd.setFormParser(fp);

        ILicenseUtil licenseUtil = SpringUtil.getBean(ILicenseUtil.class);
        Config cfg = Config.getInstance();
        if (cfg.getInt("formEditorType") == 2 && licenseUtil.isEnabled(LicenseConstUtil.FORM_DESIGNER)) {
            IFormProUtil formProUtil = SpringUtil.getBean(IFormProUtil.class);
            ftd.setFormSchemas(formProUtil.parseTable(ft.getCode(), ft.getContent()));
        }

        boolean re = ftd.save();
        if (re) {
            // 记录日志
            com.redmoon.oa.LogUtil.log(SpringUtil.getUserName(), StrUtil.getIp(request), LogDb.TYPE_ACTION, "FORM_EDIT " + ftd.getName() + ":" + ftd.getCode());

            // 当表单更新时，处理表单归档记录
            FormArchiveService formArchiveService = SpringUtil.getBean(FormArchiveService.class);
            formArchiveService.onFormUpdate(ftd);

            // 重新生成视图
            re = regenerateFormView(ft.getCode());
        }
        return re;
    }

    public boolean regenerateFormView(String formCode) {
        // 重新生成视图
        boolean re = true;
        FormParser fp = new FormParser();
        FormViewDb fvd = new FormViewDb();
        for (Object o : fvd.getViews(formCode)) {
            fvd = (FormViewDb) o;
            String form = fp.generateView(fvd.getString("content"), fvd.getString("ie_version"), formCode);
            fvd.set("form", form);
            try {
                re = fvd.save();
            } catch (ResKeyException e) {
                LogUtil.getLog(getClass()).error(e);
            }
        }
        return re;
    }

    public boolean saveWriteProp(HttpServletRequest request) throws ErrMsgException {
        String formCode = ParamUtil.get(request, "code");
        String scene = ParamUtil.get(request, "scene");

        FormDb fd = new FormDb();
        fd = fd.getFormDb(formCode);
        String writeProp = fd.getWriteProp();                   //从数据库获取回写

        SAXBuilder parser = new SAXBuilder();
        org.jdom.Document doc = null;
        Element root = null;
        Element child = null;
        List list = null;
        Iterator ir = null;

        String writeBackFormCode  = ParamUtil.get(request,"relateCode");           //回写表单
        String writeBackTime = ParamUtil.get(request,"timestamp");                //回写时间
        int repeatCount = ParamUtil.getInt(request,"repeatCount", 0);              //回写字段数量     <![CDATA[文本内容]]>
        String conditionStr = ParamUtil.get(request,"condition");

        int writeBackType = ParamUtil.getInt(request, "writeBackType", WorkflowPredefineDb.WRITE_BACK_UPDATE);
        String primaryKey = ParamUtil.get(request, "primaryKey");

        Element nodeToDel = null;
        // 条件
        Element cond = null;

        try {
            if (writeProp != null && !"".equals(writeProp)) {
                doc = parser.build(new InputSource(new StringReader(writeProp)));
                root = doc.getRootElement();

                // 核定节点通过
                list = root.getChildren("node");
                if (list != null) {
                    ir = list.iterator();
                    while (ir.hasNext()) {
                        Element nodeFinish = (Element) ir.next();
                        Element internalNode = nodeFinish.getChild("scene");
                        String internalNodeText = internalNode.getText();
                        if (scene.equals(internalNodeText)) { // 节点存在先删除
                            String writeBackOld = nodeFinish.getChildText("writeBackForm");
                            if (writeBackOld.equals(writeBackFormCode)) {
                                cond = nodeFinish.getChild("condition");
                            }
                            nodeToDel = nodeFinish;
                        }
                    }
                }
                child = new Element("node");
                Element internalNode = new Element("scene");
                internalNode.setText(scene);
                child.addContent(internalNode);

                if (nodeToDel != null) {
                    root.removeContent(nodeToDel);
                }
            } else {  // 如果writeProp为空，新建root元素
                doc = new org.jdom.Document();
                root = new Element("root");
                doc.addContent(root);

                child = new Element("node");
                Element internalNode = new Element("scene");
                internalNode.setText(scene);
                child.addContent(internalNode);
            }

            child.setAttribute("id", RandomSecquenceCreator.getId(10));
            root.addContent(child);
            Element writeBackForm = new Element("writeBackForm");
            writeBackForm.setText(writeBackFormCode);
            child.addContent(writeBackForm);
            Element writeBackTypeEl = new Element("writeBackType");
            writeBackTypeEl.setText(String.valueOf(writeBackType));
            child.addContent(writeBackTypeEl);

            Element primaryKeyEl = new Element("primaryKey");
            primaryKeyEl.setText(primaryKey);
            child.addContent(primaryKeyEl);

            Element writeBackTimeStamp = new Element("writeBackTime");
            writeBackTimeStamp.setText(writeBackTime);
            child.addContent(writeBackTimeStamp);

            FormDb fdWriteBack = fd.getFormDb(writeBackFormCode);

            // 设置字段值，可能会有多个字段
            for (int i = 0; i < repeatCount; i++) {
                String field = ParamUtil.get(request, "formfield" + i);
                String math = ParamUtil.get(request, "math" + i);
                // 判断是否为字符串型，如果是则加单引号
                FormField ff = fdWriteBack.getFormField(field);
                if (ff == null) {
                    continue;
                }
                int fieldType = ff.getFieldType();
                // int、long、float、double、price类型
                if (fieldType == FormField.FIELD_TYPE_DOUBLE || fieldType == FormField.FIELD_TYPE_FLOAT || fieldType == FormField.FIELD_TYPE_INT || fieldType == FormField.FIELD_TYPE_LONG || fieldType == FormField.FIELD_TYPE_PRICE) {
                    if ("".equals(math)) {
                        math = "0";
                    }
                } else {
                    if (!math.startsWith("'")) {
                        math = StrUtil.sqlstr(math);
                    }
                }

                Element writeBackField = new Element("writeBackField");
                writeBackField.setAttribute("fieldName", field);
                child.addContent(writeBackField);
                Element writeBackMath = new Element("writeBackMath");
                writeBackMath.setText(math);
                writeBackField.addContent(writeBackMath);
            }
            if (!"".equals(conditionStr)) {
                org.jdom.Document cdoc = parser.build(new InputSource(new StringReader(conditionStr)));
                Element croot = cdoc.getRootElement();
                Element condition = croot.getChild("condition");
                child.addContent(condition.detach());
            } else {
                if (cond != null) {
                    child.addContent(cond.detach());
                }
            }

            // 处理插入
            Element fieldsToInsert = new Element("insertFields");
            child.addContent(fieldsToInsert);
            JSONObject json = new JSONObject();
            if (writeBackType==WorkflowPredefineDb.WRITE_BACK_INSERT || writeBackType==WorkflowPredefineDb.WRITE_BACK_UPDATE_INSERT) {
                // primaryKey表示插入时如果主键字段未设置，或者主键字段不存在则插入数据，故不能以此条件判断是否需保存插入插入字段的值
                // if (!"empty".equals(primaryKey)) {
                ir = fdWriteBack.getFields().iterator();
                while (ir.hasNext()) {
                    FormField ff = (FormField) ir.next();
                    String math = ParamUtil.get(request, ff.getName() + "_formula");
                    int fieldType = ff.getFieldType();
                    if (fieldType == FormField.FIELD_TYPE_DOUBLE || fieldType == FormField.FIELD_TYPE_FLOAT || fieldType == FormField.FIELD_TYPE_INT || fieldType == FormField.FIELD_TYPE_LONG || fieldType == FormField.FIELD_TYPE_PRICE) {
                        if ("".equals(math)) {
                            math = "0";
                        }
                    } else if (fieldType == FormField.FIELD_TYPE_DATE || fieldType == FormField.FIELD_TYPE_DATETIME) {
                        // 改为在插入的时候，插入null，否则在配置界面上显示为null比较难看
					/*
					if ("".equals(math)) {
						math = "null";
					}
					*/
                    } else {
                        if (!math.startsWith("'")) {
                            math = StrUtil.sqlstr(math);
                        }
                    }
                    try {
                        json.put(ff.getName(), math);
                    } catch (JSONException e) {
                        LogUtil.getLog(getClass()).error(e);
                    }
                }
            }
            fieldsToInsert.setText(json.toString());

            Format format = Format.getPrettyFormat();
            ByteArrayOutputStream byteRsp = new ByteArrayOutputStream();
            XMLOutputter xmlOut = new XMLOutputter(format);
            xmlOut.output(doc, byteRsp);
            writeProp = byteRsp.toString("utf-8");
            byteRsp.close();

            fd.setWriteProp(writeProp);
            return fd.save();
        } catch (IOException | JDOMException e) {
            LogUtil.getLog(getClass()).error(e);
        }
        return false;
    }
}
